
package bibliotheque.client;

import bibliotheque.client.remote.ToolsRemoteIS;
import bibliotheque.events.ErrorOccuredEvent;
import bibliotheque.events.ErrorOccuredListener;
import bibliotheque.events.PingResultOccuredEvent;
import bibliotheque.events.PingResultOccuredListener;
import bibliotheque.nameserver.remote.NameServerRemoteIC;
import bibliotheque.server.remote.ServerRemoteIT;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;

/**
 *
 * @author guillaume
 */
public class Tools extends UnicastRemoteObject implements ToolsRemoteIS{
    
    private ArrayList<ErrorOccuredListener> error_occured_listener;
    private ArrayList<PingResultOccuredListener> pingResultOccured_listener;
    
    private Registry registry;
    private String ip;
    private String service;
    private ServerRemoteIT server;
    
    public Tools(String service, String ip) throws RemoteException {
        this.service = service;
        this.ip = ip;
        this.pingResultOccured_listener = new ArrayList<PingResultOccuredListener>();
        this.error_occured_listener = new ArrayList<ErrorOccuredListener>();
    }
    
    public void InitiateConnection(String adresseRmi, int portRmi) {
        
        NameServerRemoteIC nameserver = null ;
        try {
            
            this.registry = LocateRegistry.getRegistry(adresseRmi,portRmi);
        } catch (RemoteException ex) {
            this.ErrorOccured("Error finding RmiRegistry : \n" + ex.getMessage());
        }
        
        try {
            /* rmiRegistry connexion, NameServer is captured */
            nameserver = (NameServerRemoteIC)this.registry.lookup(service);
        } catch (RemoteException ex) {
            this.ErrorOccured("RemoteException during the lookup function: \n" + ex.getMessage() );
        } catch (NotBoundException ex) {
            this.ErrorOccured("NotBoundException during the lookup function: \n" + ex.getMessage() );
        }
        try {
            /* Closest Server*/
            if(nameserver != null)
                this.server = (ServerRemoteIT)nameserver.GetClosestServer(this.ip);
        } catch (RemoteException ex) {
            this.ErrorOccured("RemoteException during NameServer.GetClosestServer: \n" + ex.getMessage() );
        }
    }
    
    /**
     * Add an ErrorOccuredListener to the Object
     * @param listener ErrorOccuredListener to add
     */
    public void AddErrorOccuredListener(ErrorOccuredListener listener) {
        this.error_occured_listener.add(listener);
    }
    
    /**
     * Remove an ErrorOccuredListener to the Object
     * @param listener ErrorOccuredListener to remove
     */
    public void RemoveErrorOccuredListener(ErrorOccuredListener listener) {
        this.error_occured_listener.remove(listener);
    }
    
    
    /**
     * To specifie that a new error occured
     * @param error String that describe the error
     */
    private void ErrorOccured(String error){
        ErrorOccuredEvent event = new ErrorOccuredEvent(this, error);
        for(int i=0;i<this.error_occured_listener.size();i++) {
            this.error_occured_listener.get(i).ErrorOccured(event);
        }
    }
    
    
    
    /**
     * Add a PingResultOccuredListener to the Object
     * @param listener PingResultOccuredListener to add
     */
    public void AddPingResultOccuredListener(PingResultOccuredListener listener) {
        this.pingResultOccured_listener.add(listener);
    }
    
    /**
     * Remove a PingResultOccuredListener to the Object
     * @param listener PingResultOccuredListener to remove
     */
    private void RemovePingResultOccuredListener(PingResultOccuredListener listener) {
        this.pingResultOccured_listener.remove(listener);
    }
    
    
    /**
     * To specifie that a new ping wave returns
     * @param error ArrayList of Strings which contains all the server the wave visited
     */
    private void PingResultOccured(ArrayList<String> pingResult){
        PingResultOccuredEvent event = new PingResultOccuredEvent(this, pingResult);
        for(int i=0;i<this.pingResultOccured_listener.size();i++) {
            this.pingResultOccured_listener.get(i).PingOccured(event);
        }
    }
    
    
    public void Ping() {
        try {
            this.server.Ping(this.ip,this);
        } catch (RemoteException ex) {
            this.ErrorOccured("Remote exception lors du ping : \n"+ ex.getMessage());
        }
    }
    
    public void SetPingResult(ArrayList<String> pingResult) {
        this.PingResultOccured(pingResult);
    }
    
    public String GetIp(){
        return this.ip;
    }
    
}
